package org.metasketch.editor.links;

import groovy.lang.Binding;
import groovy.lang.GroovyShell;
import javafx.geometry.Point2D;
import javafx.scene.input.MouseButton;
import javafx.scene.input.MouseEvent;
import javafx.scene.shape.Line;
import org.metasketch.diagram.javafx.graphics.BaseGraphic;
import org.metasketch.diagram.javafx.graphics.BaseLink;
import org.metasketch.editor.toolbox.IToolHandler;
import org.metasketch.editor.toolbox.advanced.ISemanticTypeTester;
import org.metasketch.graphics.Point;
import org.metasketch.javafx.graphics.JFXDiagram;
import org.metasketch.model.BaseModel;
import org.metasketch.model.CommonIdentified;

public class DefaultLinkHandler implements IToolHandler, ISemanticTypeTester {

	Line shadowLine = new Line();

	ILink link;

	// Point2D sourceAnchor;
	BaseEndConfig initialEndConfig = null;

	// String startGraphicType = null;
	BaseGraphic startObject = null;

	private boolean shadowLink = false;

	private BaseGraphic endObject;

	private Class graphicType;
	String graphicTypeName;

	protected Point2D dragAnchor;

	protected double initX;
	protected double initY;

	private JFXDiagram diagram;

	// String semanticTestScript;

	public DefaultLinkHandler(ILink link, Class graphicClass,
			String graphicTypeName) {
		this.link = link;
		this.graphicType = graphicClass;
		this.graphicTypeName = graphicTypeName;

		shadowLine.setTranslateX(0);
		shadowLine.setTranslateY(0);
		shadowLine
				.setStyle("-fx-stroke: gray; -fx-stroke-width: 3;   -fx-stroke-dash-array: 12 2 4 2;    -fx-stroke-dash-offset: 6;     -fx-stroke-line-cap: butt; -fx-opacity: 0.5;");
	}

	@Override
	public void handle(MouseEvent event, JFXDiagram jfxDiagram, BaseModel model) {
		try {

			Object source = event.getSource();

			// String graphicType;
			if (event.getEventType() == MouseEvent.MOUSE_CLICKED
					&& event.getButton() == MouseButton.PRIMARY) {

				if (!shadowLink) {

					boolean possible = false;

					// clicked on an element
					if (source instanceof BaseGraphic) {
						BaseGraphic baseGraphic = (BaseGraphic) source;
						// String graphicType = baseGraphic.getGraphicNode()
						// .getType();

						initialEndConfig = link.isPossible(baseGraphic);
						if (initialEndConfig != null) {
							// startGraphicType = graphicType;
							possible = true;
							startObject = baseGraphic;
						}
					} else

					if (source instanceof BaseLink) {
						possible = false;
						startObject = null;
						// source = null;
					} else
					// clicked on void
					{
						initialEndConfig = link.isPossible(null);
						if (initialEndConfig != null) {
							// if (link.isPossible(null)) {
							// startGraphicType = null;
							possible = true;
							startObject = null;
						}
					}

					if (possible) {

						activateLink(event, jfxDiagram);
					}

				} else {
					applyShadowLink(event, jfxDiagram, model);
				}

				event.consume();

			} else if (event.getEventType() == MouseEvent.MOUSE_MOVED) {

				if (shadowLink)
					updateShadowLine(event);

				event.consume();

			}

			// else if (event.getEventType() == MouseEvent.MOUSE_RELEASED) {
			//
			// if (shadowLink)
			// applyShadowLink(event, jfxDiagram, model);
			//
			// event.consume();
			// }

		} catch (Throwable e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}

	public void setInitDragParams(MouseEvent event) {
		if (event.getSource() instanceof BaseGraphic) {
			BaseGraphic baseGraphic = (BaseGraphic) event.getSource();
			// initX = baseGraphic.getTranslateX();
			// initY = baseGraphic.getTranslateY();
			dragAnchor = new Point2D(event.getSceneX(), event.getSceneY());

			Point completePosition = baseGraphic
					.getCompleteCoordinatesThroughParent();

			initX = completePosition.getX() + event.getX();
			initY = completePosition.getY() + event.getY();
		} else {
			dragAnchor = new Point2D(event.getSceneX(), event.getSceneY());

			initX = event.getX();
			initY = event.getY();
		}

	}

	private void activateLink(MouseEvent event, JFXDiagram jfxDiagram) {
		shadowLink = true;

		this.diagram = jfxDiagram;

		setInitDragParams(event);

		double x = event.getX();
		double y = event.getY();

		if (startObject != null) {

			setShadowLineStartPosition(x, y);

			x += startObject.getTranslateX();
			y += startObject.getTranslateY();

		} else {
			shadowLine.setStartX(x);
			shadowLine.setStartY(y);
		}

		shadowLine.setEndX(x);
		shadowLine.setEndY(y);

		jfxDiagram.addBlindNode(shadowLine);

	}

	protected void setShadowLineStartPosition(double x, double y) {

		// double x = event.getX();
		// double y = event.getY();

		if (startObject != null) {

			if (initialEndConfig == null) {

				x += startObject.getTranslateX();
				y += startObject.getTranslateY();

			} else {

				Point point = LinkEndCalculator.getCoordinates(x, y,
						startObject, initialEndConfig.getLinkEnd()
								.getOrientation());
				x = point.getX();
				y = point.getY();

			}

			shadowLine.setStartX(x);
			shadowLine.setStartY(y);
		}

		System.out.println("start :" + x + ", " + y);

	}

	private void updateShadowLine(MouseEvent event) {

		// double x = event.getX();
		// double y = event.getY();

		// if (startObject != null) {
		// x += startObject.getTranslateX();
		// y += startObject.getTranslateY();
		// }
		// if (event.getSource() instanceof BaseGraphic) {
		// BaseGraphic hoverObject = (BaseGraphic) event.getSource();
		// // if (startObject != null) {
		// x += hoverObject.getTranslateX();
		// y += hoverObject.getTranslateY();
		// // }
		// }

		double x = event.getSceneX() - dragAnchor.getX() + initX;
		double y = event.getSceneY() - dragAnchor.getY() + initY;

		// dragAnchor = new Point2D(event.getSceneX(), event.getSceneY());
		//
		// initX = baseGraphic.getTranslateX() + event.getX();
		// initY = baseGraphic.getTranslateY() + event.getY();

		setShadowLineStartPosition(x, y);

		// System.out.println(event);

		Point mousePoint = LinkEndCalculator.getCoordinates(
				shadowLine.getStartX(), shadowLine.getStartY(), x - 1, y - 1,
				2, 2, LinkEndOrientation.CLOSEST);

		shadowLine.setEndX(mousePoint.getX());
		shadowLine.setEndY(mousePoint.getY());

		System.out.println("end " + mousePoint.getX() + ", "
				+ mousePoint.getY());

		// shadowLine.setEndX(x);
		// shadowLine.setEndY(y);

	}

	private void applyShadowLink(MouseEvent event, JFXDiagram jfxDiagram,
			BaseModel model) throws Throwable {
		// jfxDiagram.removeNode(shadowLine);
		// shadowLink = false;

		cleanup();

		Object source = event.getSource();

		// boolean possible = false;

		EndType endType = null;
		// clicked on an element
		if (source instanceof BaseGraphic) {
			BaseGraphic baseGraphic = (BaseGraphic) source;
			String graphicType = baseGraphic.getGraphicNode().getType();

			endType = link.getProperFinishEndType(startObject, baseGraphic);

			if (endType == null)
				return;

			endObject = baseGraphic;

		} else
		// clicked on void
		{
			endType = link.getProperFinishEndType(startObject, null);

			if (endType == null)
				return;

			endObject = null;

		}

		buildLink(jfxDiagram, model, endType);

	}

	private void buildLink(JFXDiagram jfxDiagram, BaseModel model,
			EndType endType) throws Throwable {

		Point startPoint = new Point((int) shadowLine.getStartX(),
				(int) shadowLine.getStartY());

		Point endPoint = new Point((int) shadowLine.getEndX(),
				(int) shadowLine.getEndY());

		LinkBuilder.setupLink(link, graphicTypeName, graphicType,
				EndType.getOpposite(endType), startObject, endType, endObject,
				startPoint, endPoint, jfxDiagram, model, null, true);
	}

	public void buildLink(BaseGraphic startGraphic, BaseGraphic targetGraphic,
			JFXDiagram jfxDiagram, BaseModel model, CommonIdentified semantic, boolean takeSnapshot)
			throws Throwable {

		EndType endType = link.getProperFinishEndType(startGraphic,
				targetGraphic);

		LinkBuilder.setupLink(link, graphicTypeName, graphicType,
				EndType.getOpposite(endType), startGraphic, endType,
				targetGraphic, null, null, jfxDiagram, model, semantic,takeSnapshot);
	}

	@Override
	public void cleanup() {

		if (shadowLink) {
			diagram.removeNode(shadowLine);
			shadowLink = false;

			diagram = null;
		}

	}

	// public void setupLink(EndType endType, BaseGraphic startObject2,
	// EndType opposite, BaseGraphic endObject2, jfxDiagram) {
	//
	// }

	@Override
	public boolean isValid(CommonIdentified semantic) {

		if (link.getSemanticConfig() == null)
			return false;

		return link.getSemanticConfig().isValid(semantic);

	}

	public BaseGraphic getStartObject() {
		return startObject;
	}

	public void setStartObject(BaseGraphic startObject) {
		this.startObject = startObject;
	}

	public BaseGraphic getEndObject() {
		return endObject;
	}

	public void setEndObject(BaseGraphic endObject) {
		this.endObject = endObject;
	}

	
	//haccccckkk
	public ILink getLink() {
		return link;
	}

	// public String getSemanticTestScript() {
	// return semanticTestScript;
	// }
	//
	// public void setSemanticTestScript(String semanticTestScript) {
	// this.semanticTestScript = semanticTestScript;
	// }

}
